using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Animator;
using Box2D.XNA;
using Microsoft.Xna.Framework.Audio;
namespace TurbaconPhone
{
    public enum CharacterTeam { Red = 0, Blue };
    public enum PlayerType
    {
        forward, mid, defence
    };

    public class Character : KineticGameObject
    {
        CharDef CharDef;
        public enum CharDir { Left = 0, Right = 1 };

        public static Texture2D[] headTex = new Texture2D[2];
        public static Texture2D[] torsoTex = new Texture2D[2];
        public static Texture2D[] legsTex = new Texture2D[2];
        public static Texture2D[] weaponTex = new Texture2D[1];

        public static string ANIM_IDLE = "idle";
        public static string ANIM_RUN = "run";
        public static string ANIM_FALL = "fall";
        public static string ANIM_DEAD = "dead";
        public static string ANIM_VICTORY = "victory";
        public static string ANIM_LOSE = "lose";
        public static string ANIM_ONFIRE = "onfire";
        public static string ANIM_KICK = "kick";
        public static string ANIM_INSANITY = "insanity";
        public static string ANIM_GOALIE = "goalie";

        public PlayerType playerType;

        public const float NormalSpeed = 65f, SelectedSpeed = 100f;
        public float Speed = NormalSpeed;
        public Vector2? StopLocation = null;
        public bool FullAnim = false;
        public bool AbilityActivated = false;
        float AbilityTime = 10;
        public float AbilityTimer;
        Power AbilityIndicator;
        public CharDir Face;
        //public float Scale;
        public int AnimFrame;
        //public state?
        public int Anim;
        public String AnimName;
        public CharacterTeam Team = CharacterTeam.Red;
        public SoundEffect kick, pew;

        public bool flying = false;

        public Brain brain;

        float frame = 0f;


        public Character(Vector2 pos, CharDef newCharDef, PlayerType playerType, CharacterTeam team, CharDir dir) : base("None", pos)
        {
            this.playerType = playerType;
            this.Team = team;
            this.Face = dir;
            brain = new Brain(this);
            Face = CharDir.Left;
            Scale = 0.5f;
            CharDef = newCharDef;
            kick = TurBacon.Content.GetSound("kick1");
            pew = TurBacon.Content.GetSound("pew");
            
            SetAnim("idle");

            CreateBody(pos);

            TrailColor = Color.Red;
            AbilityTimer = TurBacon.RandomBetween(AbilityTime/2, AbilityTime);
            
        }

        private void CreateBody(Vector2 pos)
        {
            if (Body != null)
                Physics.World.DestroyBody(Body);
            BodyDef def = new BodyDef();
            def.position = pos/Physics.WorldScale;
            def.type = BodyType.Dynamic;
            Body = Physics.World.CreateBody(def);
            Body.SetUserData(this);

            PolygonShape shape = new PolygonShape();
            shape.SetAsBox(32 / (2 * Physics.WorldScale), 32 / (2 * Physics.WorldScale));
            Fixture = Body.CreateFixture(shape, 1);
            Fixture.SetRestitution(0);

            Body.SetAngularDamping(10000);
            Body.SetLinearDamping(1);
        }
        internal static void LoadTextures()
        {
            for (int i = 0; i < headTex.Length; i++)
            {
                headTex[i] = TurBacon.Content.GetTexture("gfx/head" + (i + 1).ToString());
            }
            for (int i = 0; i < torsoTex.Length; i++)
            {
                torsoTex[i] = TurBacon.Content.GetTexture("gfx/torso" + (i + 1).ToString());
            }
            for (int i = 0; i < legsTex.Length; i++)
            {
                legsTex[i] = TurBacon.Content.GetTexture("gfx/legs" + (i + 1).ToString());
            }
            for (int i = 0; i < weaponTex.Length; i++)
            {
                weaponTex[i] = TurBacon.Content.GetTexture("gfx/weapon" + (i + 1).ToString());
            }
        }

        public void SetAnim(string newAnim)
        {
            if (AnimName == newAnim) return;

            for (int i = 0; i < CharDef.Animations.Length; i++)
            {
                if (CharDef.Animations[i].name == newAnim)
                {
                    Anim = i;
                    AnimFrame = 0;
                    frame = 0;
                    AnimName = newAnim;

                    break;
                }
            }

        }

        #region Physics
        public override void Bump(object obj)
        {
            if (obj is Ball)
            {
                if (((Ball)obj).OnFire && !this.OnFire)
                {
                    new Fire("explosion", 5, this, 0.5f);
                    new Smoke("smoke", 5, this, 1f);
                }

            }
            base.Bump(obj);
        }



        #endregion
        #region Commands
        public void Move(Vector2 target)
        {
            Vector2 dir = target - (this.Pos + new Vector2(-10, -50)) ; //HARDCORE HACK FIX OH YEA BABY

            if (dir.X > 0) Face = CharDir.Right;
            else Face = CharDir.Left;

            SetAnim(ANIM_RUN);

            dir.Normalize();

            Vel = dir * Speed;
            StopLocation = target;
            //base.Move(dir);
        }

        public void Stop()
        {
            StopLocation = null;
            SetAnim("idle");
            Vel = Vector2.Zero;
        }

        public void Kick(Vector2 force)
        {
            StopLocation = null;
            foreach (Character ch in TurBacon.GameInfo.Characters)
            {
                if (ch != this )
                {
                    Vector2 delta = (ch.Pos - this.Pos);
                    if (delta.Length() <= 100)
                    {
                        delta.Normalize();
                        ch.Flying(delta * 300);
                    }
                }
            }
            kick.Play();
            if (force.X > 0) Face = CharDir.Right;
            else Face = CharDir.Left;

            SetAnim(ANIM_KICK);
            FullAnim = true;
        }
        public void Flying(Vector2 force)
        {
            pew.Play();
            StopLocation = null;
            if (force.X > 0) Face = CharDir.Left;
            else Face = CharDir.Right;
            this.Vel = force;
            brain.BrainState = BrainState.action;
            SetAnim(ANIM_FALL);
            FullAnim = true;
            flying = true;
        }
        public void Dead()
        {
            StopLocation = null;
            flying = false;
            SetAnim(ANIM_DEAD);
            FullAnim = true;
        }

        public void Teleport(Vector2 pos)
        {
            CreateBody(pos);
        }

        public void TeleportAbility(Vector2 pos)
        {
            if (AbilityTimer != 0)
                return;
            new Explosion("explosion2", Pos);
            Teleport(pos);
            AbilityUsed();
            new Explosion("explosion2", pos);
        }

        #endregion

        #region Update and Draw
        public override void Update(GameTime gameTime)
        {
            float et = (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (!FullAnim)
           
            {
                if (OnFire)
                {
                    //Stop();
                    StopLocation = null;
                    
                    Vel = Vector2.Zero;
                    if (TurBacon.Random.Next(10) == 5)
                    {
                        if (Face == CharDir.Left) Face = CharDir.Right;
                        else Face = CharDir.Left;
                    }

                    SetAnim(ANIM_ONFIRE);
                }
                else
                if (Vel.Length() <= 15 && !flying && !TurBacon.GameInfo.gameOver) SetAnim(ANIM_IDLE);
            }

            AbilityTimer -= (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (AbilityTimer < 0)
            {
                if (AbilityIndicator == null) AbilityIndicator = new Power("explosion4", 9999, this, 1f);
                AbilityTimer = 0;
            }


            if(StopLocation.HasValue && !TurBacon.GameInfo.gameOver)
            {
                Move((Vector2)StopLocation);

                if (this.Contains((Vector2)StopLocation))
                {         
                    Stop();
                }
            }
            #region Animation
            Animator.Animation animation = CharDef.Animations[Anim];
            KeyFrame keyFrame = animation.KeyFrames[AnimFrame];

            frame += et * 30.0f;
            
            if (frame > (float)keyFrame.Duration)
            {
                frame -= (float)keyFrame.Duration;
                AnimFrame++;
                if (AnimFrame >= animation.KeyFrames.Length)
                    AnimFrame = 0;

                keyFrame = animation.KeyFrames[AnimFrame];

                if (keyFrame.FrameRef < 0)
                {
                    AnimFrame = 0;
                    if(FullAnim) FullAnim = false;
                }
            }
            #endregion
            if (!TurBacon.GameInfo.gameOver)
            {
                brain.Update(gameTime);
            }

            base.Update(gameTime);
        }
        
        public override void  Draw(SpriteBatch spriteBatch)
        {
 	 
            Rectangle sRect = new Rectangle();

            int frameIndex = CharDef.Animations[Anim].KeyFrames[AnimFrame].FrameRef;

            Frame frame = CharDef.Frames[frameIndex];

            for (int i = 0; i < frame.Parts.Length; i++)
            {
                Part part = frame.Parts[i];
                if (part.Index > -1)
                {
                    sRect.X = ((part.Index % 64) % 5) * 64;
                    sRect.Y = ((part.Index % 64) / 5) * 64;
                    sRect.Width = 64;
                    sRect.Height = 64;

                    if (part.Index >= 192)
                    {
                        sRect.X = ((part.Index % 64) % 3) * 80;
                        sRect.Width = 80;
                    }

                    float rotation = part.Rotation;

                    Vector2 location = part.Location * Scale + Pos + new Vector2(-10, 32);
                    Vector2 scaling = part.Scaling * Scale;

                    if (part.Index >= 128) scaling *= 1.35f;

                    if (Face == CharDir.Right)
                    {
                        rotation = -rotation;
                        location.X -= part.Location.X * Scale * 2.0f;
                    }

                    Texture2D texture = null;

                    int t = part.Index / 64;
                    switch (t)
                    {
                        case 0:
                            texture = headTex[CharDef.HeadIndex];
                            break;
                        case 1:
                            texture = torsoTex[CharDef.TorsoIndex];
                            break;
                        case 2:
                            texture = legsTex[CharDef.LegsIndex];
                            break;
                        case 3:
                            texture = weaponTex[CharDef.WeaponIndex];
                            break;
                    }

                    Color color = new Color(new Vector4(1f, 1f, 1f, 1f));

                    

                    bool flip = false;

                    if ((Face == CharDir.Left && part.Flip == 0) || (Face == CharDir.Right && part.Flip == 1)) flip = true;

                    if (texture != null)
                    {
                        TurBacon.Batch.Draw(texture, location, sRect, color, rotation, new Vector2((float)sRect.Width / 2f, (float)sRect.Height / 2f), scaling, (flip ? SpriteEffects.None : SpriteEffects.FlipHorizontally), 1.0f);
                    }
                }
            }
            //DebugDraw(TurBacon.Batch);
        }

        #endregion

        public void AbilityUsed()
        {
            AbilityActivated = false;
            AbilityTimer = TurBacon.RandomBetween(AbilityTime / 2, AbilityTime);
            if (AbilityIndicator != null)
            {
                AbilityIndicator.Die();
                AbilityIndicator = null;
            }
        }
    }
}
